package com.skjd.service.seq.range.impl.db;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.skjd.entity.SeqRange;
import com.skjd.entity.XSequenceSequenceModel;
import com.skjd.mapper.XSequenceSequenceMapper;
import com.skjd.seq.exception.SeqException;
import com.skjd.service.SeqRangeMgr;


@Service
public class DbSeqRangeMgr implements SeqRangeMgr{
	
	/* <!-- 数据源[必选] -->
     <property name="dataSource" ref="dataSource"/>
     <!-- 表名[可选] 默认：sequence-->
     <property name="tableName" value="sequence"/>
     <!-- 更新失败重试次数[可选] 默认：100-->
     <property name="retryTimes" value="100"/>
     <!-- 每次取数步长[可选] 默认：1000-->
     <property name="step" value="1000"/>
     <!-- 起始数，注意真实开始可用数是stepStart+1，例如stepStart=0表示从1开始[可选] 默认：0-->
     <property name="stepStart" value="0"/>	*/
	@Autowired
	private XSequenceSequenceMapper  xSequenceSequenceMapper ;
	
    /**
     * 表名前缀，为防止数据库表名冲突，默认带上这个前缀
     */
    private final static String TABLENAME_PREFIX = "x_sequence_";

    /**
     * 区间步长
     */
    private static int  step       = 1000;
    /**
     * 区间起始位置，真实从stepStart+1开始
     */
    private  static long stepStart  = 1000000;
    /**
     * 获取区间失败重试次数
     */
    private  static int  retryTimes = 100;
  
    /**
     * 表名，默认range
     */
    private static String tableName = "range";
	
    private static final long DELTA = 100000000L;
	
	@Override
	public SeqRange nextRange(String name) throws SeqException {
        if (isEmpty(name)) {
            throw new SecurityException("[DbSeqRangeMgr-nextRange] name is empty.");
        }

        Long oldValue;
        Long newValue;

        for (int i = 0; i < getRetryTimes(); i++) {
            
        	//oldValue = DbHelper.selectRange(getDataSource(), getRealTableName(), name, getStepStart());
        	oldValue = selectRange(name);
            
            if (null == oldValue) {
                //区间不存在，重试
                continue;
            }
            newValue = oldValue + getStep();
            int result = updateRange(newValue,oldValue,name);
            if (result > 0) {
            	 return new SeqRange(oldValue + 1, newValue);
            }
        }

        throw new SeqException("Retried too many times, retryTimes = " + getRetryTimes());
	}
	
	
	/**
	 * 
	 * @param newValue 新值
	 * @param oldValue 旧值
	 * @return
	 */
	public  int updateRange(Long newValue,Long oldValue,String name){
		int result = 1 ;
		
		XSequenceSequenceModel  xsequence = new XSequenceSequenceModel();
		xsequence.setValue(oldValue+newValue);
		xsequence.setOldvalue(oldValue);
		//xsequence.setName(name);
		xsequence.setGmtModified(new Date());
		result = xSequenceSequenceMapper.updateXSequenceSequence(xsequence);
		return result;
	}
	
	/**
	 * 查询值
	 * @return
	 */
	public Long selectRange(String name){
		  long oldValue;
		  XSequenceSequenceModel  xsequence = new XSequenceSequenceModel();
          xsequence.setName(name);
          List<String> queryFields  =  new ArrayList<String>();
          queryFields.add("value");
          XSequenceSequenceModel model =  xSequenceSequenceMapper.queryXSequenceSequenceById(xsequence, queryFields);
          if (model == null) {
          	XSequenceSequenceModel save = new XSequenceSequenceModel();
          	save.setName(name);
          	save.setValue(stepStart);
          	save.setGmtCreate(new Date());
          	save.setGmtModified(new Date());
          	xSequenceSequenceMapper.addXSequenceSequence(save);
          	 return null;
          }
          oldValue = model.getValue();

          if (oldValue < 0) {
              String msg =
                      "Sequence value cannot be less than zero, value = " + oldValue + ", please check table sequence"
                      + tableName;
              throw new SeqException(msg);
          }

          if (oldValue > Long.MAX_VALUE - DELTA) {
              String msg =
                      "Sequence value overflow, value = " + oldValue + ", please check table sequence" + tableName;
              throw new SeqException(msg);
          }
          return oldValue ;
	}
	@Override
	public void init() {
		checkParam();
		
	}

	
    private void checkParam() {
        if (step <= 0) {
            throw new SecurityException("[DbSeqRangeMgr-checkParam] step must greater than 0.");
        }
        if (stepStart < 0) {
            throw new SecurityException("[DbSeqRangeMgr-setStepStart] stepStart < 0.");
        }
        if (retryTimes <= 0) {
            throw new SecurityException("[DbSeqRangeMgr-setRetryTimes] retryTimes must greater than 0.");
        }
        if (isEmpty(tableName)) {
            throw new SecurityException("[DbSeqRangeMgr-setTableName] tableName is empty.");
        }
    }
    
    private boolean isEmpty(String str) {
        return null == str || str.trim().length() == 0;
    }

	public static int getStep() {
		return step;
	}

	public static void setStep(int step) {
		DbSeqRangeMgr.step = step;
	}

	public static long getStepStart() {
		return stepStart;
	}

	public static void setStepStart(long stepStart) {
		DbSeqRangeMgr.stepStart = stepStart;
	}

	public static int getRetryTimes() {
		return retryTimes;
	}

	public static void setRetryTimes(int retryTimes) {
		DbSeqRangeMgr.retryTimes = retryTimes;
	}

	public static String getTableName() {
		return tableName;
	}

	public static void setTableName(String tableName) {
		DbSeqRangeMgr.tableName = tableName;
	}

	public static String getTablenamePrefix() {
		return TABLENAME_PREFIX;
	}
    
    
}
